using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace SqlTools.DataAccessLibrary
{
	public delegate void DbListItemAdded<OBJ>(object sender, DbListItemAddedEventArgs<OBJ> e);
	public delegate void DbListItemChanged<OBJ>(object sender, DbListItemChangedEventArgs<OBJ> e);
	public delegate void DbListItemRemoved<OBJ>(object sender, DbListItemRemovedEventArgs<OBJ> e);

	public class DbList<T> : IList<T>
		where T : BusinessObject
	{
		protected List<T> _list;

		public event EventHandler Saving;
		public event EventHandler Saved;
		public event EventHandler Deleting;
		public event EventHandler Deleted;

		public event DbListItemAdded<T> ItemAdded;
		public event DbListItemChanged<T> ItemChanged;
		public event DbListItemRemoved<T> ItemRemoved;

		public DbList()
		{
			_list = new List<T>();
		}

		public DbList(int capacity)
		{
			_list = new List<T>(capacity);
		}

		public DbList(IEnumerable<T> collection)
		{
			_list = new List<T>(collection);

			foreach ( T item in collection )
			{
				OnItemAdded(item);
			}
		}

		#region IList<T> Members

		public int IndexOf(T item)
		{
			return _list.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			_list.Insert(index, item);
			// todo: fire added event

			OnItemAdded(item);
		}

		public void RemoveAt(int index)
		{
			T item = _list[index];

			_list.RemoveAt(index);

			OnItemRemoved(item);
		}

		public T this[int index]
		{
			get
			{
				return _list[index];
			}
			set
			{
				T prevItem = _list[index];
				
				_list[index] = value;

				OnItemChanged(prevItem, value);
			}
		}
		#endregion

		#region ICollection<T> Members

		public void Add(T item)
		{
			( (ICollection<T>)_list ).Add(item);

			OnItemAdded(item);
		}

		public void Clear()
		{
			foreach ( T item in _list )
			{
				OnItemRemoved(item);
			}

			( (ICollection<T>)_list ).Clear();
		}

		public bool Contains(T item)
		{
			return ( (ICollection<T>)_list ).Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			( (ICollection<T>)_list ).CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return ( (ICollection<T>)_list ).Count; }
		}

		public bool IsReadOnly
		{
			get { return ( (ICollection<T>)_list ).IsReadOnly; }
		}

		public bool Remove(T item)
		{
			bool removed = ( (ICollection<T>)_list ).Remove(item);
		
			if ( removed )
				OnItemRemoved(item);

			return removed;
		}

		#endregion

		#region IEnumerable<T> Members

		public IEnumerator<T> GetEnumerator()
		{
			return _list.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return ( (IEnumerable)_list ).GetEnumerator();
		}

		#endregion

		public void Save()
		{
			OnSaving();

			foreach ( T item in _list )
			{
				item.Save();
			}
			
			OnSaved();
		}

		public void Delete()
		{
			OnDeleting();
			
			foreach ( T item in _list )
			{
				item.Delete();
			}

			OnDeleted();
		}

		#region EventLaunchers
		protected virtual void OnSaving()
		{
			if ( this.Saving != null )
				this.Saving(this, new EventArgs());
		}

		protected virtual void OnSaved()
		{
			if ( this.Saved != null )
				this.Saved(this, new EventArgs());
		}

		protected virtual void OnDeleting()
		{
			if ( this.Deleting != null )
				this.Deleting(this, new EventArgs());
		}

		protected virtual void OnDeleted()
		{
			if ( this.Deleted != null )
				this.Deleted(this, new EventArgs());
		}
		
		protected void OnItemAdded(T item)
		{
			if ( ItemAdded != null )
			{
				item.Deleted += new BusinessObjectEvent(item_Deleted);
				ItemAdded(this, new DbListItemAddedEventArgs<T>(item));
			}
		}

		protected void OnItemChanged(T previousItem, T newItem)
		{
			if ( ItemChanged != null )
			{
				previousItem.Deleted -= new BusinessObjectEvent(item_Deleted);
				newItem.Deleted += new BusinessObjectEvent(item_Deleted);
				ItemChanged(this, new DbListItemChangedEventArgs<T>(previousItem, newItem));
			}
		}

		protected void OnItemRemoved(T item)
		{
			if ( ItemRemoved != null )
			{
				item.Deleted -= new BusinessObjectEvent(item_Deleted);
				ItemRemoved(this, new DbListItemRemovedEventArgs<T>(item));
			}
		}
		#endregion

		#region EventHandlers
		void item_Deleted(object sender, BusinessObjectEventArgs e)
		{
			this._list.Remove((T)e.Item);
		}
		#endregion
	}
}
